package pl.softech.engine3d.screen;
import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Window;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;

import javax.swing.JFrame;


/**
 *  Klasa <class>ScreenManager</class>
 *  @author Sławomir Śledź
 *  @version 1.0
 */
public class ScreenManager {

	private GraphicsDevice device;
	
	public ScreenManager() {
		GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
		device = env.getDefaultScreenDevice();
	}
	
	public DisplayMode[] getCompatibleDisplayModes() { return device.getDisplayModes(); }
	
	public JFrame getFullScreenWindow() { return (JFrame) device.getFullScreenWindow(); }
	
	public DisplayMode findFirstCompatibleMode(DisplayMode[] modes) {
		DisplayMode[] goodModes = device.getDisplayModes();
		for(int i = 0; i < modes.length; i++)
			for(int j = 0; j < goodModes.length; j++)
				if(isDisplayModesMatch(modes[i], goodModes[j]))
					return modes[i];
		return null;
	}
	
	public DisplayMode getCurrentDisplayMode() { return device.getDisplayMode(); }
	
	private boolean isDisplayModesMatch(DisplayMode m1, DisplayMode m2) {
		
		if(m1.getHeight() != m2.getHeight() || m1.getWidth() != m2.getWidth())
			return false;
		
		if (m1.getBitDepth() != m2.getBitDepth()
				&& m1.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI
				&& m2.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI)
			return false;
		
		if(m1.getRefreshRate() != m2.getRefreshRate() 
				&& m1.getRefreshRate() != DisplayMode.REFRESH_RATE_UNKNOWN
				&& m2.getRefreshRate() != DisplayMode.REFRESH_RATE_UNKNOWN)
			return false;
		
		return true;
	}
	
	public void setFullScreen(DisplayMode mode) {
		final JFrame window = new JFrame();
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		window.setUndecorated(true);
		window.setResizable(false);
		window.setIgnoreRepaint(true);
		device.setFullScreenWindow(window);
		
		if(mode == null || !device.isDisplayChangeSupported()) {
			System.err.println("Bład podczas zmiany trybu wyświetlania");
			return; 
		}
		
		try {
			device.setDisplayMode(mode);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		}
		// poprawka dla systemu MacOS X
		window.setSize(mode.getWidth(), mode.getHeight());

		// Unikanie potencjalnego zakleszczenia w wersji 1.4
		try {
			EventQueue.invokeAndWait(new Runnable() {

				@Override
				public void run() {
					window.createBufferStrategy(2);

				}

			});
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * Pobiera kontekst graficzny dla ekranu. ScreenManager korzysta z
	 * podwójnego buforowania, więc aplikacje muszą wywoływać metodę update() w
	 * celu odrysowania grafiki na ekranie.
	 */
	public Graphics2D getGraphics() {
		Window window = getFullScreenWindow();
		if(window != null) {
			BufferStrategy s = window.getBufferStrategy();
			return (Graphics2D)s.getDrawGraphics();
		}
		return null;
	}
	
	/**
	 * Odrysowuje ekran
	 */
	public void update() {
		Window window = getFullScreenWindow();
		if(window == null) return;
		BufferStrategy strategy = window.getBufferStrategy();
		if(!strategy.contentsLost())
			strategy.show();
	}
	
	/**
	 * Powraca do poprzedniego trybu
	 */
	public void restoreScreen() {
		JFrame w = getFullScreenWindow();
		if(w != null)
			w.dispose();
		device.setFullScreenWindow(null);
	}
	
	/**
	 * Zwraca szerokość okna użytego w trybie pełnoekranowym. Zwraca 0
	 * jeśli urządzenie nie jest w trybie pełnoekranowym. 
	 */
	public int getWidth() {
		Window window = getFullScreenWindow();
		if(window != null)
			return window.getWidth();
		return 0;
	}
	
	/**
	 * Zwraca wysokość okna użytego w trybie pełnoekranowym. Zwraca 0
	 * jeśli urządzenie nie jest w trybie pełnoekranowym. 
	 */
	public int getHeight() {
		Window window = getFullScreenWindow();
		if(window != null)
			return window.getHeight();
		return 0;
	}
	
	/**
	 * Tworzy obiekt Image zgodny z bierzącym ekranem
	 */
	public BufferedImage createCompatibleImage(int width, int height, int transparency) {
		Window window = getFullScreenWindow();
		if(window == null) return null;
		
		GraphicsConfiguration gc = window.getGraphicsConfiguration();
		return gc.createCompatibleImage(width, height, transparency);
		
	}
	
	public static void main(String[] args) {
		ScreenManager m = new ScreenManager();
//		m.setFullScreen(new DisplayMode(1024, 756, 24, DisplayMode.REFRESH_RATE_UNKNOWN));
		m.setFullScreen(GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode());
		Graphics2D g = m.getGraphics();
		g.setColor(Color.BLACK);
		g.fill(new Rectangle2D.Double(0, 0, (double)m.getWidth(), (double)m.getHeight()));
		g.dispose();
		m.update();
		try {
			Thread.sleep(5 * 1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			m.restoreScreen();
		}
	}
	
}
